<template>
    <view class="blue_tooth">
        <view>
            <u-button type="success" shape="square" :disabled="buttonStatus===1" @click="discovery">搜索附近蓝牙设备
            </u-button>
            <scroll-view scroll-y="true" class="box">
                <view class="item" v-for="item in blueDeviceList" v-if="item.name && item.localName">
                    <view @click="connect(item)">
                        <text>名称: {{ item.name || item.localName }}</text>
                    </view>
                </view>
            </scroll-view>
            <u-button type="warning" shape="square" :disabled="buttonStatus===2" @click="stopDiscovery">停止搜索
            </u-button>

            <view v-if="deviceId">当前连接蓝牙ID：{{ deviceId }}</view>
            <view v-if="serviceId">当前连接服务ID：{{ serviceId }}</view>
            <view v-if="characteristicId">当前连接特征值ID：{{ characteristicId }}</view>
            <u-button type="success" shape="square" :disabled="!connectStatus" @click="getServices">获取蓝牙服务
            </u-button>

            <scroll-view scroll-y="true" class="box">
                <view class="item" v-for="item in allServices" v-if="item.uuid">
                    <view @click="() => serviceId = item.uuid">
                        <text style="display: block">uuid: {{ item.uuid }}</text>
                        <text>isPrimary: {{ item.isPrimary }}</text>
                    </view>
                </view>
            </scroll-view>

            <u-button type="success" shape="square" :disabled="!serviceId" @click="getCharacteristics">获取特征值
            </u-button>
            <!--            <text v-if="allCharacteristics">特征值列表: {{JSON.stringify(allCharacteristics)}}</text>-->

            <scroll-view scroll-y="true" class="box">
                <view class="item" v-for="item in allCharacteristics" v-if="item.uuid">
                    <view @click="selectCharacteristic(item)">
                        <text style="display: block">uuid: {{ item.uuid }}</text>
                        <text>读: {{ item.properties.read }} - 写: {{ item.properties.write }} - notify:
                            {{ item.properties.notify }} - indicate: {{ item.properties.indicate }}
                        </text>
                    </view>
                </view>
            </scroll-view>


            <u-button type="success" shape="square" :disabled="!characteristicId || !canNotify" @click="startNotify">开启消息监听
            </u-button>


            <u-button type="success" shape="square" :disabled="!characteristicId || !canWrite" @click="selectFile">选择文件</u-button>
            <u-button type="success" shape="square" :disabled="!characteristicId || !canWrite || !selectedFilePath" @click="send">发送文件</u-button>

            <u-button type="success" shape="square" :disabled="!characteristicId || !canRead" @click="read">读取数据</u-button>

            <!-- 音频播放控制 -->
            <view class="audio-controls">
                <u-button type="primary" shape="square" :disabled="!characteristicId || !canWrite || !selectedFilePath" @click="startAudioStream">开始音频流传输</u-button>
                <u-button type="warning" shape="square" :disabled="!isStreaming" @click="stopAudioStream">停止音频流</u-button>
                <u-button type="info" shape="square" :disabled="!characteristicId || !canWrite" @click="sendAudioCommand">发送音频控制指令</u-button>
            </view>

            <!-- 选择的文件信息 -->
            <view v-if="selectedFileName" class="file-info">
                <view class="file-name">已选择文件: {{ selectedFileName }}</view>
                <view class="file-path">路径: {{ selectedFilePath }}</view>
            </view>

            <!-- 音频状态信息 -->
            <view v-if="isStreaming" class="audio-status">
                <view class="status-title">音频流状态</view>
                <view class="status-item">状态: 正在传输</view>
                <view class="status-item">格式: {{ audioFormat }}</view>
                <view class="status-item">采样率: {{ sampleRate }}Hz</view>
                <view class="status-item">声道: {{ channels }}</view>
                <view class="status-item">位深度: {{ bitDepth }}bit</view>
            </view>

            <!-- 文件发送进度 -->
            <view v-if="sendingFile" class="progress-container">
                <view class="progress-text">发送进度: {{ sendProgress }}%</view>
                <view class="progress-bar">
                    <view class="progress-fill" :style="{ width: sendProgress + '%' }"></view>
                </view>
                <view class="progress-info">已发送: {{ sentChunks }}/{{ totalChunks }} 块</view>
            </view>


            <view class="msg_x">
                <view class="msg_txt">
                    监听到的内容：{{ message }}
                </view>
                <view class="msg_hex">
                    监听到的内容（十六进制）：{{ messageHex }}
                </view>
            </view>
        </view>

        <u-toast ref="uToast"/>
        <u-modal v-model="show" :content="content" @confirm="confirm"></u-modal>
    </view>
</template>

<script>
export default {
    data() {
        return {
            errorMsg: '',
            blueDeviceList: [], // 搜索到的蓝牙设备列表
            buttonStatus: 2, // 1 搜索中 2 停止搜索
            deviceId: '', // 连接设备id
            show: false,
            content: '',
            connectStatus: false, // 连接状态
            allServices: [], // 所有服务
            serviceId: '', // 当前服务id
            allCharacteristics: [], // 所有特征值
            characteristicId: '', // 当前特征值id
            message: '', // 监听到的内容
            messageHex: '', // 监听到的内容（十六进制）
            canRead: false, // 是否支持读取
            canWrite: false, // 是否支持写入
            canNotify: false, // 是否支持通知
            sendingFile: false, // 是否正在发送文件
            sendProgress: 0, // 发送进度百分比
            sentChunks: 0, // 已发送的块数
            totalChunks: 0, // 总块数
            selectedFilePath: '', // 选择的文件路径
            selectedFileName: '', // 选择的文件名
            isStreaming: false, // 是否正在音频流传输
            audioContext: null, // 音频上下文
            audioSource: null, // 音频源
            streamInterval: null, // 音频流定时器
            audioData: null, // 音频数据
            audioFormat: 'PCM', // 音频格式 (PCM, MP3, AAC)
            sampleRate: 44100, // 采样率
            channels: 2, // 声道数
            bitDepth: 16 // 位深度
        };
    },
    methods: {
        discovery() {
            this.initBlue();
        },


        // 【1】初始化蓝牙
        initBlue() {
            const that = this;
            uni.openBluetoothAdapter({
                success(res) {
                    that.showToast('初始化蓝牙成功')
                    that.errorMsg = res && res.errMsg;
                    console.log(res)
                    that.startDiscovery();
                },
                fail(err) {
                    that.showToast('初始化蓝牙失败', 'warning')
                    that.errorMsg = err && err.errMsg;
                    console.error(err)
                }
            })
        },

        // 【2】开始搜寻附近设备
        startDiscovery() {
            const that = this;
            that.buttonStatus = 1;
            uni.startBluetoothDevicesDiscovery({
                success(res) {
                    // 开启监听回调
                    uni.onBluetoothDeviceFound(that.found)
                },
                fail(err) {
                    console.log('搜索失败')
                    that.showToast('搜索失败: ' + err.errMsg, 'warning')
                    console.error(err)
                }
            })
        },
        // 【3】找到新设备就触发该方法
        found(res) {
            this.blueDeviceList.push(res.devices[0])
            /* {
                 "devices": [{
                 "deviceId": "B4:10:7B:C4:83:14",
                 "name": "蓝牙设备名",
                 "RSSI": -58,
                 "localName": "",
                 "advertisServiceUUIDs": ["0000FFF0-0000-1000-8000-00805F9B34FB"],
                 "advertisData": {}
             }]
             }*/
            console.log('blueDeviceList: ', this.blueDeviceList)
        },

        connect(data) {
            this.deviceId = data.deviceId
            this.showModal('是否连接蓝牙设备: ' + data.name || data.localName)
        },
        confirm() {
            this.startConnect()
        },

        // 【4】连接设备
        startConnect() {
            let that = this
            uni.createBLEConnection({
                deviceId: that.deviceId,
                success() {
                    that.showToast('连接成功')
                    that.connectStatus = true
                    // 停止搜索
                    setTimeout(() => {
                        that.stopDiscovery()
                    }, 3000)
                },
                fail(err) {
                    that.showToast('连接失败: ' + err.errMsg, 'warning')
                    console.error(err)
                }
            })
        },

        // 【5】停止搜索
        stopDiscovery() {
            const that = this;
            that.buttonStatus = 2;
            uni.stopBluetoothDevicesDiscovery({
                success() {
                    console.log('停止搜索成功')
                    that.showToast('停止搜索成功')
                },
                fail(err) {
                    console.log('停止搜索失败')
                    that.showToast('停止搜索失败: ' + err.errMsg, 'warning')
                }
            })
        },

        // 【6】获取蓝牙服务
        getServices() {
            let that = this
            uni.getBLEDeviceServices({
                deviceId: that.deviceId, // 设备ID，在上一步【4】里获取
                success(res) {
                    console.log(res)
                    that.showToast('获取蓝牙服务成功')
                    that.allServices = res.services
                },
                fail(err) {
                    that.showToast('获取蓝牙服务失败: ' + err.errMsg, 'warning')
                    console.error(err)
                }
            })
        },

        // 【7】获取特征值
        getCharacteristics() {
            let that = this
            uni.getBLEDeviceCharacteristics({
                deviceId: that.deviceId, // 设备ID
                serviceId: that.serviceId, // 服务ID
                success(res) {
                    console.log(res)
                    that.allCharacteristics = res.characteristics
                    that.showToast('获取特征值成功')
                },
                fail(err) {
                    console.error(err)
                    that.showToast('获取特征值失败: ' + err.errMsg, 'warning')
                }
            })
        },

        // 选择特征值并验证属性
        selectCharacteristic(item) {
            this.characteristicId = item.uuid
            this.canRead = item.properties.read || false
            this.canWrite = item.properties.write || false
            this.canNotify = item.properties.notify || item.properties.indicate || false
            
            console.log('选择的特征值:', item.uuid)
            console.log('支持读取:', this.canRead)
            console.log('支持写入:', this.canWrite)
            console.log('支持通知:', this.canNotify)
            
            this.showToast(`已选择特征值: ${item.uuid}`)
        },


        // 【8】开启消息监听
        startNotify() {
            let that = this
            
            // 验证特征值是否支持通知
            if (!that.canNotify) {
                that.showToast('当前特征值不支持通知功能', 'warning')
                return
            }
            
            uni.notifyBLECharacteristicValueChange({
                deviceId: that.deviceId, // 设备ID，在【4】里获取到
                serviceId: that.serviceId, // 服务ID，在【6】里能获取到, // 服务UUID，在【6】里能获取到
                characteristicId: that.characteristicId, // 特征值，在【7】里能获取到
                state: true, // 启用通知，必需参数
                success(res) {
                    console.log(res)
                    that.showToast('开启消息监听成功')
                    // 接受消息的方法
                    that.listenValueChange()
                },
                fail(err) {
                    console.error(err)
                    that.showToast('开启消息监听失败: ' + err.errMsg, 'warning')
                }
            })
        },


        // 【9】监听消息变化
        listenValueChange() {
            let that = this
            uni.onBLECharacteristicValueChange(res => {
                // 结果
                console.log(res)

                // 结果里有个value值，该值为 ArrayBuffer 类型，所以在控制台无法用肉眼观察到，必须将该值转换为16进制
                let resHex = that.ab2hex(res.value)
                console.log(resHex)
                that.messageHex = resHex
                // 最后将16进制转换为ascii码，就能看到对应的结果
                let result = that.hexCharCodeToStr(resHex)
                console.log(result)
                that.message = result
            })
        },
        // ArrayBuffer转16进度字符串示例
        ab2hex(buffer) {
            const hexArr = Array.prototype.map.call(
                    new Uint8Array(buffer),
                    function (bit) {
                        return ('00' + bit.toString(16)).slice(-2)
                    }
            )
            return hexArr.join('')
        },
        // 将16进制的内容转成我们看得懂的字符串内容
        hexCharCodeToStr(hexCharCodeStr) {
            var trimedStr = hexCharCodeStr.trim();
            var rawStr = trimedStr.substr(0, 2).toLowerCase() === "0x" ? trimedStr.substr(2) : trimedStr;
            var len = rawStr.length;
            if (len % 2 !== 0) {
                alert("存在非法字符!");
                return "";
            }
            var curCharCode;
            var resultStr = [];
            for (var i = 0; i < len; i = i + 2) {
                curCharCode = parseInt(rawStr.substr(i, 2), 16);
                resultStr.push(String.fromCharCode(curCharCode));
            }
            return resultStr.join("");
        },


        // 【10】发送数据
        send() {
            let that = this
            
            // 验证特征值是否支持写入
            if (!that.canWrite) {
                that.showToast('当前特征值不支持写入功能', 'warning')
                return
            }
            
            // 发送MP3音频文件
            that.sendMP3File()
        },

        // 选择文件
        selectFile() {
            const that = this
            
            // #ifdef APP-PLUS
            // APP端使用文件选择器
            uni.chooseFile({
                count: 1,
                type: 'file',
                extension: ['.mp3', '.wav', '.aac'],
                success(res) {
                    console.log('选择文件成功:', res)
                    that.selectedFilePath = res.tempFilePaths[0]
                    that.selectedFileName = res.tempFiles[0].name
                    that.showToast(`已选择文件: ${that.selectedFileName}`)
                },
                fail(err) {
                    console.error('选择文件失败:', err)
                    that.showToast('选择文件失败: ' + err.errMsg, 'warning')
                }
            })
            // #endif
            
            // #ifdef H5
            // H5端使用input file
            const input = document.createElement('input')
            input.type = 'file'
            input.accept = '.mp3,.wav,.aac'
            input.onchange = (e) => {
                const file = e.target.files[0]
                if (file) {
                    that.selectedFilePath = URL.createObjectURL(file)
                    that.selectedFileName = file.name
                    that.showToast(`已选择文件: ${that.selectedFileName}`)
                }
            }
            input.click()
            // #endif
            
            // #ifdef MP-WEIXIN
            // 微信小程序使用文件选择器
            uni.chooseMessageFile({
                count: 1,
                type: 'file',
                success(res) {
                    console.log('选择文件成功:', res)
                    that.selectedFilePath = res.tempFiles[0].path
                    that.selectedFileName = res.tempFiles[0].name
                    that.showToast(`已选择文件: ${that.selectedFileName}`)
                },
                fail(err) {
                    console.error('选择文件失败:', err)
                    that.showToast('选择文件失败: ' + err.errMsg, 'warning')
                }
            })
            // #endif
        },

        // 发送选择的文件
        sendMP3File() {
            const that = this
            
            if (!that.selectedFilePath) {
                that.showToast('请先选择要发送的文件', 'warning')
                return
            }
            
            // 读取选择的文件
            that.readSelectedFile()
        },

        // 读取选择的文件
        readSelectedFile() {
            const that = this
            
            console.log('开始读取文件:', that.selectedFilePath)
            
            // #ifdef H5
            // H5端需要特殊处理
            if (that.selectedFilePath.startsWith('blob:')) {
                // 如果是blob URL，需要先获取文件数据
                fetch(that.selectedFilePath)
                    .then(response => response.arrayBuffer())
                    .then(buffer => {
                        console.log('文件读取成功，大小:', buffer.byteLength, '字节')
                        that.showToast(`文件读取成功，大小: ${(buffer.byteLength / 1024).toFixed(2)}KB`)
                        that.sendFileInChunks(buffer)
                    })
                    .catch(err => {
                        console.error('文件读取失败:', err)
                        that.showToast('文件读取失败: ' + err.message, 'warning')
                    })
                return
            }
            // #endif
            
            // 其他平台使用文件系统管理器
            uni.getFileSystemManager().readFile({
                filePath: that.selectedFilePath,
                success(res) {
                    console.log('文件读取成功，大小:', res.data.byteLength, '字节')
                    that.showToast(`文件读取成功，大小: ${(res.data.byteLength / 1024).toFixed(2)}KB`)
                    
                    // 分块发送文件
                    that.sendFileInChunks(res.data)
                },
                fail(err) {
                    console.error('文件读取失败:', err)
                    that.showToast('文件读取失败: ' + err.errMsg, 'warning')
                }
            })
        },

        // 分块发送文件
        sendFileInChunks(fileData) {
            const that = this
            const chunkSize = 512 // 每次发送512字节，避免超出蓝牙MTU限制
            const totalSize = fileData.byteLength
            let currentOffset = 0
            let chunkIndex = 0
            
            // 初始化进度
            that.sendingFile = true
            that.sendProgress = 0
            that.sentChunks = 0
            that.totalChunks = Math.ceil(totalSize / chunkSize)
            
            console.log(`开始分块发送文件，总大小: ${totalSize} 字节，块大小: ${chunkSize} 字节，总块数: ${that.totalChunks}`)
            
            const sendNextChunk = () => {
                if (currentOffset >= totalSize) {
                    that.showToast('文件发送完成！')
                    console.log('文件发送完成')
                    that.sendingFile = false
                    return
                }
                
                const endOffset = Math.min(currentOffset + chunkSize, totalSize)
                const chunk = fileData.slice(currentOffset, endOffset)
                
                console.log(`发送第 ${chunkIndex + 1} 块，偏移: ${currentOffset}-${endOffset-1}，大小: ${chunk.byteLength} 字节`)
                
                uni.writeBLECharacteristicValue({
                    deviceId: that.deviceId,
                    serviceId: that.serviceId,
                    characteristicId: that.characteristicId,
                    value: chunk,
                    success(res) {
                        console.log(`第 ${chunkIndex + 1} 块发送成功`)
                        currentOffset = endOffset
                        chunkIndex++
                        
                        // 更新进度
                        that.sentChunks = chunkIndex
                        that.sendProgress = Math.round((currentOffset / totalSize) * 100)
                        
                        // 延迟发送下一块，避免发送过快
                        setTimeout(() => {
                            sendNextChunk()
                        }, 50) // 50ms延迟
                    },
                    fail(err) {
                        console.error(`第 ${chunkIndex + 1} 块发送失败:`, err)
                        that.showToast(`第 ${chunkIndex + 1} 块发送失败: ` + err.errMsg, 'warning')
                        that.sendingFile = false
                    }
                })
            }
            
            // 开始发送第一块
            sendNextChunk()
        },

        // 开始音频流传输
        startAudioStream() {
            const that = this
            
            if (!that.selectedFilePath) {
                that.showToast('请先选择音频文件', 'warning')
                return
            }
            
            // 读取音频文件并开始流传输
            that.prepareAudioStream()
        },

        // 准备音频流
        prepareAudioStream() {
            const that = this
            
            console.log('准备音频流传输...')
            
            // #ifdef H5
            // H5端使用Web Audio API
            if (that.selectedFilePath.startsWith('blob:')) {
                fetch(that.selectedFilePath)
                    .then(response => response.arrayBuffer())
                    .then(buffer => {
                        that.audioData = buffer
                        that.startH5AudioStream()
                    })
                    .catch(err => {
                        console.error('音频文件读取失败:', err)
                        that.showToast('音频文件读取失败: ' + err.message, 'warning')
                    })
                return
            }
            // #endif
            
            // 其他平台使用文件系统管理器
            uni.getFileSystemManager().readFile({
                filePath: that.selectedFilePath,
                success(res) {
                    that.audioData = res.data
                    that.startAudioStreaming()
                },
                fail(err) {
                    console.error('音频文件读取失败:', err)
                    that.showToast('音频文件读取失败: ' + err.errMsg, 'warning')
                }
            })
        },

        // H5端音频流传输
        startH5AudioStream() {
            const that = this
            
            try {
                // 创建音频上下文
                that.audioContext = new (window.AudioContext || window.webkitAudioContext)()
                
                // 解码音频数据
                that.audioContext.decodeAudioData(that.audioData)
                    .then(audioBuffer => {
                        console.log('音频解码成功:', audioBuffer)
                        that.streamAudioBuffer(audioBuffer)
                    })
                    .catch(err => {
                        console.error('音频解码失败:', err)
                        that.showToast('音频解码失败: ' + err.message, 'warning')
                    })
            } catch (err) {
                console.error('创建音频上下文失败:', err)
                that.showToast('创建音频上下文失败: ' + err.message, 'warning')
            }
        },

        // 流式传输音频缓冲区
        streamAudioBuffer(audioBuffer) {
            const that = this
            
            that.isStreaming = true
            that.showToast('开始音频流传输')
            
            const sampleRate = audioBuffer.sampleRate
            const channels = audioBuffer.numberOfChannels
            const length = audioBuffer.length
            
            console.log(`音频信息: 采样率=${sampleRate}, 声道数=${channels}, 长度=${length}`)
            
            // 设置流传输参数
            const chunkSize = 1024 // 每次发送1024个样本
            const bytesPerSample = 2 // 16位音频
            const bytesPerChunk = chunkSize * channels * bytesPerSample
            
            let currentSample = 0
            
            that.streamInterval = setInterval(() => {
                if (currentSample >= length) {
                    that.stopAudioStream()
                    return
                }
                
                // 获取当前块的音频数据
                const endSample = Math.min(currentSample + chunkSize, length)
                const chunkLength = endSample - currentSample
                
                // 创建音频数据缓冲区
                const audioChunk = new ArrayBuffer(chunkLength * channels * bytesPerSample)
                const view = new DataView(audioChunk)
                let offset = 0
                
                // 混合所有声道的数据
                for (let i = 0; i < chunkLength; i++) {
                    for (let ch = 0; ch < channels; ch++) {
                        const sample = audioBuffer.getChannelData(ch)[currentSample + i]
                        const int16Sample = Math.max(-32768, Math.min(32767, sample * 32767))
                        view.setInt16(offset, int16Sample, true) // 小端序
                        offset += 2
                    }
                }
                
                // 发送音频数据
                that.sendAudioChunk(audioChunk)
                
                currentSample = endSample
                
                // 显示进度
                const progress = Math.round((currentSample / length) * 100)
                console.log(`音频流进度: ${progress}%`)
                
            }, 50) // 50ms间隔，约20fps
        },

        // 发送音频数据块
        sendAudioChunk(chunk) {
            const that = this
            
            uni.writeBLECharacteristicValue({
                deviceId: that.deviceId,
                serviceId: that.serviceId,
                characteristicId: that.characteristicId,
                value: chunk,
                success(res) {
                    // 音频流发送成功
                },
                fail(err) {
                    console.error('音频数据发送失败:', err)
                    that.showToast('音频数据发送失败: ' + err.errMsg, 'warning')
                    that.stopAudioStream()
                }
            })
        },

        // 开始音频流传输（通用方法）
        startAudioStreaming() {
            const that = this
            
            that.isStreaming = true
            that.showToast('开始音频流传输')
            
            // 发送音频格式信息
            that.sendAudioFormatInfo()
            
            // 开始分块发送音频数据
            that.streamAudioData()
        },

        // 发送音频格式信息
        sendAudioFormatInfo() {
            const that = this
            
            const formatInfo = {
                format: that.audioFormat,
                sampleRate: that.sampleRate,
                channels: that.channels,
                bitDepth: that.bitDepth
            }
            
            const buffer = new ArrayBuffer(16)
            const view = new DataView(buffer)
            
            // 写入格式信息
            view.setUint8(0, 0xFF) // 格式标识
            view.setUint8(1, 0x01) // 版本
            view.setUint16(2, that.sampleRate, true) // 采样率
            view.setUint8(4, that.channels) // 声道数
            view.setUint8(5, that.bitDepth) // 位深度
            view.setUint32(6, that.audioData.byteLength, true) // 数据长度
            
            uni.writeBLECharacteristicValue({
                deviceId: that.deviceId,
                serviceId: that.serviceId,
                characteristicId: that.characteristicId,
                value: buffer,
                success(res) {
                    console.log('音频格式信息发送成功')
                },
                fail(err) {
                    console.error('音频格式信息发送失败:', err)
                }
            })
        },

        // 流式发送音频数据
        streamAudioData() {
            const that = this
            
            const chunkSize = 512 // 每次发送512字节
            const totalSize = that.audioData.byteLength
            let currentOffset = 0
            
            const sendNextChunk = () => {
                if (!that.isStreaming || currentOffset >= totalSize) {
                    if (currentOffset >= totalSize) {
                        that.showToast('音频流传输完成')
                    }
                    that.stopAudioStream()
                    return
                }
                
                const endOffset = Math.min(currentOffset + chunkSize, totalSize)
                const chunk = that.audioData.slice(currentOffset, endOffset)
                
                uni.writeBLECharacteristicValue({
                    deviceId: that.deviceId,
                    serviceId: that.serviceId,
                    characteristicId: that.characteristicId,
                    value: chunk,
                    success(res) {
                        currentOffset = endOffset
                        
                        // 显示进度
                        const progress = Math.round((currentOffset / totalSize) * 100)
                        console.log(`音频流进度: ${progress}%`)
                        
                        // 继续发送下一块
                        setTimeout(() => {
                            sendNextChunk()
                        }, 20) // 20ms间隔，约50fps
                    },
                    fail(err) {
                        console.error('音频数据发送失败:', err)
                        that.showToast('音频数据发送失败: ' + err.errMsg, 'warning')
                        that.stopAudioStream()
                    }
                })
            }
            
            // 开始发送
            sendNextChunk()
        },

        // 停止音频流
        stopAudioStream() {
            const that = this
            
            that.isStreaming = false
            
            if (that.streamInterval) {
                clearInterval(that.streamInterval)
                that.streamInterval = null
            }
            
            if (that.audioContext) {
                that.audioContext.close()
                that.audioContext = null
            }
            
            that.showToast('音频流传输已停止')
            console.log('音频流传输已停止')
        },

        // 发送音频控制指令
        sendAudioCommand() {
            const that = this
            
            const commands = [
                { name: '播放', code: 0x01 },
                { name: '暂停', code: 0x02 },
                { name: '停止', code: 0x03 },
                { name: '音量+', code: 0x04 },
                { name: '音量-', code: 0x05 },
                { name: '下一曲', code: 0x06 },
                { name: '上一曲', code: 0x07 }
            ]
            
            // 显示命令选择
            uni.showActionSheet({
                itemList: commands.map(cmd => cmd.name),
                success(res) {
                    const command = commands[res.tapIndex]
                    that.sendCommand(command.code)
                }
            })
        },

        // 发送控制指令
        sendCommand(commandCode) {
            const that = this
            
            const buffer = new ArrayBuffer(2)
            const view = new DataView(buffer)
            view.setUint8(0, 0xFE) // 指令标识
            view.setUint8(1, commandCode) // 指令代码
            
            uni.writeBLECharacteristicValue({
                deviceId: that.deviceId,
                serviceId: that.serviceId,
                characteristicId: that.characteristicId,
                value: buffer,
                success(res) {
                    console.log('控制指令发送成功:', commandCode)
                    that.showToast('控制指令发送成功')
                },
                fail(err) {
                    console.error('控制指令发送失败:', err)
                    that.showToast('控制指令发送失败: ' + err.errMsg, 'warning')
                }
            })
        },


        // 【11】读取数据
        read() {
            let that = this
            
            // 验证特征值是否支持读取
            if (!that.canRead) {
                that.showToast('当前特征值不支持读取功能', 'warning')
                return
            }
            
            uni.readBLECharacteristicValue({
                deviceId: that.deviceId,
                serviceId: that.serviceId,
                characteristicId: that.characteristicId,
                success(res) {
                    that.showToast('读取指令发送成功')
                    console.log(res)
                },
                fail(err) {
                    console.log('读取指令发送失败')
                    that.showToast('读取指令发送失败: ' + err.errMsg, 'warning')
                    console.error(err)
                }
            })
        },


        showToast(title, type = 'success', duration = 3000) {
            this.$refs.uToast.show({title, type, duration})
        },

        showModal(content) {
            this.show = true
            this.content = content
        }
        ,

    }
}
</script>

<style lang="scss">
.blue_tooth {
    padding: 20upx;
}

button {
    margin: 20upx 0;
}

.box {
    width: 100%;
    max-height: 600upx;
    box-sizing: border-box;
    margin-bottom: 20upx;
}

.item {
    box-sizing: border-box;
    padding: 15upx;
    border-bottom: 1px solid #dedede;
}

.progress-container {
    margin: 20upx 0;
    padding: 20upx;
    background-color: #f5f5f5;
    border-radius: 10upx;
}

.progress-text {
    font-size: 28upx;
    color: #333;
    margin-bottom: 10upx;
}

.progress-bar {
    width: 100%;
    height: 20upx;
    background-color: #ddd;
    border-radius: 10upx;
    overflow: hidden;
    margin-bottom: 10upx;
}

.progress-fill {
    height: 100%;
    background-color: #007aff;
    transition: width 0.3s ease;
}

.progress-info {
    font-size: 24upx;
    color: #666;
}

.file-info {
    margin: 20upx 0;
    padding: 15upx;
    background-color: #e8f4fd;
    border-radius: 8upx;
    border-left: 4upx solid #007aff;
}

.file-name {
    font-size: 28upx;
    color: #333;
    font-weight: bold;
    margin-bottom: 5upx;
}

.file-path {
    font-size: 24upx;
    color: #666;
    word-break: break-all;
}

.audio-controls {
    margin: 20upx 0;
    padding: 20upx;
    background-color: #f0f8ff;
    border-radius: 10upx;
    border: 1px solid #007aff;
}

.audio-controls button {
    margin: 10upx;
}

.audio-status {
    margin: 20upx 0;
    padding: 20upx;
    background-color: #fff3cd;
    border-radius: 10upx;
    border: 1px solid #ffc107;
}

.status-title {
    font-size: 28upx;
    font-weight: bold;
    color: #856404;
    margin-bottom: 10upx;
}

.status-item {
    font-size: 24upx;
    color: #856404;
    margin: 5upx 0;
}
</style>
